﻿/*
 * This file is part of MonoStrategy.
 *
 * Copyright (C) 2010-2011 Christoph Husse
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: 
 *      # Christoph Husse
 * 
 * Also checkout our homepage: http://monostrategy.codeplex.com/
 */
using System;
using System.IO;
using System.Runtime.Serialization;

namespace MonoStrategy
{
    public interface ISoundPlayer
    {
        void Dispose();
        void Play(Int64 inDelayMillis);
        void Stop();
        Animation Animation { get; }
    }

    public class AudioObject
    {
        public Int64 Checksum { get; private set; }
        public AnimationLibrary Library { get; private set; }
        public String Name { get; internal set; }
        public Int32 UsageCount { get; internal set; }
        public TimeSpan Duration { get; internal set; }
        internal byte[] m_AudioBytes;

        internal void Save(BinaryWriter inWriter)
        {
            // write audio to stream
            inWriter.Write((Byte)6); // audio type ID
            inWriter.Write((UInt16)0x1000); // audio version

            inWriter.Write((String)Name);
            inWriter.Write((Int64)Checksum);
            inWriter.Write((Int32)UsageCount);
            inWriter.Write((Int64)Duration.Ticks);
        }

        internal static AudioObject Load(AnimationLibrary inLibrary, BinaryReader inReader)
        {
            AudioObject result = new AudioObject();

            if (inReader.ReadByte() != 6)
                throw new InvalidDataException();

            switch (inReader.ReadUInt16())
            {

                case 0x1000:
                    {
                        result.Name = inReader.ReadString();
                        result.Checksum = inReader.ReadInt64();
                        result.UsageCount = inReader.ReadInt32();
                        result.Duration = new TimeSpan(inReader.ReadInt64());
                    } break;
                default:
                    throw new InvalidDataException();
            }

            result.Library = inLibrary;

            return result;
        }

        private AudioObject()
        {
        }

        internal AudioObject(AnimationLibrary inLibrary, byte[] inAudioData) 
        {
            if (inLibrary == null)
                throw new ArgumentNullException();

            m_AudioBytes = inAudioData;
            Library = inLibrary;
            byte[] hash = System.Security.Cryptography.MD5.Create().ComputeHash(new MemoryStream(inAudioData));

            Checksum = 0;

            for (int i = 0; i < 8; i++)
            {
                Checksum |= (((Int64)hash[i]) << (i * 8));
            }

            // validate file
            CreatePlayer(null).Dispose();

            //Duration = ComputeDuration();
        }

        //private TimeSpan ComputeDuration()
        //{
        //    WaveStream readerStream = new WaveFileReader(new MemoryStream(m_AudioBytes));

        //    try
        //    {
        //        WaveChannel32 waveStream = new WaveChannel32(readerStream);

        //        using (waveStream)
        //        {
        //            return waveStream.TotalTime;
        //        }
        //    }
        //    finally
        //    {
        //        readerStream.Dispose();
        //    }
        //}

        internal void Load()
        {
            if (m_AudioBytes == null)
                m_AudioBytes = Library.LoadAudio(this);
        }

        private class SoundPlayer : System.Media.SoundPlayer, ISoundPlayer
        {
            public Animation Animation { get; set; }

            public SoundPlayer(byte[] inAudioBytes) : base(new MemoryStream(inAudioBytes))
            {
            }

            public void Play(Int64 inDelayMillis)
            {
                if (inDelayMillis <= 0)
                {
                    Play();
                }
                else
                {
                    AnimationUtilities.SynchronizeTask(inDelayMillis, () => { Play(); });
                }
            }
        }

        public ISoundPlayer CreatePlayer(Animation inAnimation)
        {
            Load();

            SoundPlayer result = new SoundPlayer(m_AudioBytes);

            result.Animation = inAnimation;

            return result;
        }
    }
}
